home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / demos / OpenGL / fontflip / fontflip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  14.8 KB  |  635 lines

  1. /*
  2.  * Copyright (C) 1995, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * UNPUBLISHED -- Rights reserved under the copyright laws of the United
  6.  * States.  Use of a copyright notice is precautionary only and does not
  7.  * imply publication or disclosure.
  8.  *
  9.  * THIS SOFTWARE CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION OF
  10.  * SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION, DISTRIBUTION, OR
  11.  * DISCLOSURE IS STRICTLY PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN
  12.  * PERMISSION OF SILICON GRAPHICS, INC.
  13.  *
  14.  * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND
  15.  * Use, duplication or disclosure by the Government is subject to restrictions
  16.  * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the
  17.  * Rights in Technical Data and Computer Software clause at DFARS 252.227-7013
  18.  * and/or in similar or successor clauses in the FAR, or the DOD or NASA FAR
  19.  * Supplement.  Unpublished-- rights reserved under the copyright laws of the
  20.  * United States. Contractor/manufacturer is Silicon Graphics, Inc.,
  21.  * 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <math.h>
  28. #include <GL/gl.h>
  29. #include <GL/glc.h>
  30. #include <GL/glu.h>
  31. #include <Xm/Xm.h>
  32. #include <Xm/Form.h>
  33. #include <Xm/Frame.h>
  34. #include <Xm/RowColumn.h>
  35. #include <Xm/ToggleBG.h>
  36. #include <Xm/CascadeBG.h>
  37. #include <X11/keysym.h>
  38. #include <GL/GLwMDrawA.h>
  39. #include <alloca.h>
  40.  
  41.  
  42. int attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
  43.           GLX_RED_SIZE, 1, GLX_BLUE_SIZE, 1,
  44.           GLX_GREEN_SIZE, 1, None};
  45.  
  46. String fallbackResources[] = {
  47.     "*sgiMode: True",
  48.     "*useSchemes: all",
  49.     "*canvas.width: 300", "*canvas.height: 300",
  50.     "*frame.shadowType: SHADOW_IN",
  51.     NULL};
  52.  
  53. GLuint contextID;
  54. GLfloat rotX, rotY, rotZ, scale;
  55. GLfloat transX, transY, transZ;
  56. GLfloat origX, origY;
  57. GLfloat zsize;
  58. GLfloat bounds[8];
  59. int glx_width, glx_height;
  60.  
  61. GLint fontID, *fontIDs, fontCount;
  62. char **fontNames;
  63.  
  64. char *default_str = "hello, world!";
  65. char *render_str;
  66.  
  67. int drawStyle;
  68. int use_ortho;
  69.  
  70. enum {
  71.     XX_BITMAP,
  72.     XX_TRIANGLE,
  73.     XX_LINE,
  74.     XX_RESETVIEW,
  75.     XX_RESETMODE,
  76.     XX_ORTHO,
  77.     XX_QUIT,
  78.     NULL_COMMAND
  79. };
  80.  
  81. GLXContext glxctx;
  82. Widget canvas;
  83. Widget *menu_buttons;
  84. int fontBase;
  85.  
  86. /* menus */
  87. typedef struct {
  88.     char *label;
  89.     int cmd;
  90. } MenuItem;
  91.  
  92. typedef struct {
  93.     char *label;
  94.     int icount;
  95.     MenuItem *items;
  96. } MenuPane;
  97.  
  98. MenuItem view_items[] = {
  99.     { "Reset View", XX_RESETVIEW },
  100.     { "Reset Modes", XX_RESETMODE },
  101.     { "Ortho Projection", XX_ORTHO },
  102.     { "Quit", XX_QUIT },
  103. };
  104.  
  105. MenuItem style_items[] = {
  106.     { "GLC_BITMAP", XX_BITMAP },
  107.     { "GLC_TRIANGLE", XX_TRIANGLE },
  108.     { "GLC_LINE", XX_LINE },
  109. };
  110.  
  111. MenuPane view_menu = { "View", XtNumber(view_items), view_items };
  112. MenuPane style_menu = { "Render Style", XtNumber(style_items), style_items };
  113.  
  114. void InitFonts(void)
  115. {
  116.     int ii;
  117.     char *ptr;
  118.  
  119.     if ((contextID = glcGenContext()) == 0) {
  120.     printf("Died at glcGenContext\n");
  121.     exit(1);
  122.     }
  123.  
  124.     glcContext(contextID);
  125.     if (glcGetError() != GL_NO_ERROR) {
  126.     printf("Died at glcContext\n");
  127.     exit(1);
  128.     }
  129.  
  130.     fontCount = glcGeti(GLC_MASTER_COUNT);
  131.     if (glcGetError() != GL_NO_ERROR) {
  132.     printf("Died at glcGeti\n");
  133.     exit(1);
  134.     }
  135.  
  136.     if (fontCount <= 0) {
  137.     fprintf(stderr, "No available fonts\n");
  138.     exit(1);
  139.     }
  140.  
  141.     fontIDs = (GLint *) malloc ( fontCount * sizeof(GLint) );
  142.     bzero(fontIDs, fontCount * sizeof(GLint));
  143.     fontNames = (char **) malloc ( fontCount * sizeof(char *) );
  144.  
  145.     for (ii = 0; ii < fontCount; ii++) {
  146.     fontNames[ii] = strdup((char *)glcGetMasterc(ii, GLC_FAMILY));
  147. #if 0
  148.     /* We *could* load all the fonts now, but it slows initialization.
  149.      * Instead we'll lazy-load them.
  150.      */
  151.     fontIDs[ii] = glcGenFontID();
  152.     if (glcNewFontFromMaster(fontIDs[ii], ii) != fontIDs[ii]) {
  153.         printf("Died at glcNewFontFromMaster\n");
  154.         exit(1);
  155.     }
  156. #endif
  157.     }
  158.  
  159.     fontID = -1;
  160. }
  161.  
  162. void set_toggle(int button, int set)
  163. {
  164.     XmToggleButtonGadgetSetState(menu_buttons[button], set, False);
  165. }
  166.  
  167. void set_font(int id)
  168. {
  169.     if (fontID >= 0)
  170.     set_toggle(fontID + fontBase, False);
  171.  
  172.     fontID = id;
  173.     set_toggle(fontID + fontBase, True);
  174.  
  175.     if (!fontIDs[id]) {
  176.     fontIDs[id] = glcGenFontID();
  177.     if (glcNewFontFromMaster(fontIDs[id], id) != fontIDs[id]) {
  178.         printf("Died at glcNewFontFromMaster\n");
  179.         exit(1);
  180.     }
  181.     }
  182.  
  183.     glcFont(fontIDs[fontID]);
  184. }
  185.  
  186. void set_draw_style(int style)
  187. {
  188.     int ii;
  189.     for (ii = XX_BITMAP; ii <= XX_LINE; ii++)
  190.     set_toggle(ii, style == ii);
  191.  
  192.     switch (style) {
  193.     case XX_BITMAP:
  194.     drawStyle = GLC_BITMAP;
  195.     break;
  196.     case XX_LINE:
  197.     drawStyle = GLC_LINE;
  198.     break;
  199.     case XX_TRIANGLE:
  200.     default:
  201.     drawStyle = GLC_TRIANGLE;
  202.     break;
  203.     }
  204.     glcRenderStyle(drawStyle);
  205. }
  206.  
  207. void reset_bounds()
  208. {
  209.     GLfloat width = 0.0, height = 0.0;
  210.  
  211.     if (drawStyle == GLC_BITMAP)
  212.     glcLoadIdentity();
  213.     if (glcMeasureString(GL_TRUE, render_str) != 0) {
  214.     glcGetStringMetric(GLC_BOUNDS, bounds);
  215.     width = bounds[2] - bounds[0];
  216.     height = bounds[5] - bounds[3];
  217.     }
  218.     origX = - width / 2.0;
  219.     origY = - height / 2.0;
  220. }
  221.  
  222. void reset_view()
  223. {
  224.     set_toggle(XX_RESETVIEW, False);
  225.  
  226.     rotX = rotY = rotZ = 0.0;
  227.     scale = 55.0;
  228.     transX = 0.0;
  229.     transY = 0.0;
  230.     transZ = 0.0;
  231.     zsize = 10.0;
  232.     reset_bounds();
  233. }
  234.  
  235. void reset_modes()
  236. {
  237.     set_toggle(XX_RESETMODE, False);
  238.     set_draw_style(XX_LINE);
  239.     use_ortho = False;
  240.     if (render_str && render_str != default_str)
  241.     free(render_str);
  242.     render_str = default_str;
  243. }
  244.  
  245. void redraw(void)
  246. {
  247.     glClear(GL_COLOR_BUFFER_BIT);
  248.  
  249.     glPushMatrix();
  250.     glTranslatef(transX, transY, transZ);
  251.     glScalef(scale, scale, 1.0);
  252.     glRotatef(rotX, 1.0, 0.0, 0.0);
  253.     glRotatef(rotY, 0.0, 1.0, 0.0);
  254.     glRotatef(rotZ, 0.0, 0.0, 1.0);
  255.     glTranslatef(origX, origY, 0.0);
  256.  
  257.     /* Draw the bounding box */
  258.     glColor3f(1.0, 1.0, 1.0);
  259.     glBegin(GL_LINE_LOOP);
  260.     glVertex3f(bounds[0], bounds[1], 0.0);
  261.     glVertex3f(bounds[2], bounds[3], 0.0);
  262.     glVertex3f(bounds[4], bounds[5], 0.0);
  263.     glVertex3f(bounds[6], bounds[7], 0.0);
  264.     glEnd();
  265.  
  266.  
  267.     if (drawStyle != GLC_BITMAP) {
  268.     glColor3f(0.0, 1.0, 0.0);
  269.     glcRenderString(render_str);
  270.     glPopMatrix();
  271.     } else {
  272. #if 1
  273.     /* This section is a hack to ensure that the raster position is
  274.      * valid and the string is not clipped, even if the origin is
  275.      * outside the viewport.  First we calculate the transformed
  276.      * origin...
  277.      */
  278.     GLdouble mvmat[16], prjmat[16], x, y, z;
  279.     GLint vp[4];
  280.     glGetDoublev(GL_MODELVIEW_MATRIX, mvmat);
  281.     glGetDoublev(GL_PROJECTION_MATRIX, prjmat);
  282.     glGetIntegerv(GL_VIEWPORT, vp);
  283.     gluProject(0, 0, 0, mvmat, prjmat, vp, &x, &y, &z);
  284.  
  285.     /* Now pop the transformation since we no longer need it */
  286.     glPopMatrix();
  287.  
  288.     /* Map window coordinates to world coordinates */
  289.     x -= vp[2] >> 1;
  290.     y -= vp[3] >> 1;
  291.  
  292.     /* Set the raster position to something valid (0,0) and translate
  293.      * it to the transformed origin.  This keeps it valid, even though
  294.      * it may be outside of the viewport!
  295.      */
  296.     glColor3f(1.0, 0.0, 0.0);
  297.     glRasterPos3f(0, 0, z);
  298.     glBitmap(0, 0, 0, 0, x, y, NULL);
  299.     glcLoadIdentity();
  300.     glcScale(scale, scale);
  301.     glcRotate(-rotZ);
  302.     glcRenderString(render_str);
  303. #else
  304.     /* If we don't care about the string being clipped, we could always
  305.      * specify the raster position directly.  Here, (0,0) is transformed
  306.      * to the desired raster position.  Note that moving the origin
  307.      * outside of the viewport clips the entire string.
  308.      */
  309.     glColor3f(1.0, 0.0, 0.0);
  310.     glRasterPos3f(0, 0, 0);
  311.     glcLoadIdentity();
  312.     glcScale(scale, scale);
  313.     glcRotate(-rotZ);
  314.     glcRenderString(render_str);
  315.     glPopMatrix();
  316. #endif
  317.     }
  318.  
  319.  
  320.     if (glcGetError() != GL_NO_ERROR) {
  321.     printf("Got a GLC error\n");
  322.     exit(1);
  323.     }
  324.  
  325.     glXSwapBuffers(XtDisplay(canvas), XtWindow(canvas));
  326. }
  327.  
  328. void expose(Widget w, XtPointer ctx, XtPointer call)
  329. {
  330.     redraw();
  331. }
  332.  
  333. void reset_proj()
  334. {
  335.     set_toggle(XX_ORTHO, use_ortho);
  336.  
  337.     if (use_ortho) {
  338.     glMatrixMode(GL_PROJECTION);
  339.     glLoadIdentity();
  340.     glOrtho(-glx_width/2, glx_width/2, -glx_height/2, glx_height/2,
  341.         0, zsize);
  342.     glMatrixMode(GL_MODELVIEW);
  343.     glLoadIdentity();
  344.     } else {
  345.     glMatrixMode(GL_PROJECTION);
  346.     glLoadIdentity();
  347.     gluPerspective(360 * atanf(glx_height / zsize) / M_PI,
  348.                (GLfloat)glx_width / glx_height,
  349.                0.0, zsize);
  350.     glMatrixMode(GL_MODELVIEW);
  351.     glLoadIdentity();
  352.     }
  353.  
  354.     glTranslatef(0.0, 0.0, -zsize/2.0);
  355. }
  356.  
  357. static void resize(Widget w, XtPointer ctx, XtPointer call)
  358. {
  359.     GLwDrawingAreaCallbackStruct *data;
  360.     data = (GLwDrawingAreaCallbackStruct *) call;
  361.  
  362.     glXWaitX();
  363.     glx_width = data->width;
  364.     glx_height = data->height;
  365.     glViewport(0, 0, data->width, data->height);
  366.     reset_proj();
  367. }
  368.  
  369. static void initCB(Widget w, XtPointer ctx, XtPointer call)
  370. {
  371.     glXMakeCurrent(XtDisplay(w), XtWindow(w), ctx);
  372.     glClearColor(0.0, 0.0, 0.0, 0.0);
  373.     set_font(0);
  374.     reset_modes();
  375.     reset_view();
  376.     resize(w, ctx, call);
  377. }
  378.  
  379. static void input(Widget w, XtPointer ctx, XtPointer call)
  380. {
  381.     char buf[31];
  382.     KeySym keysym;
  383.     XEvent *event = ((GLwDrawingAreaCallbackStruct *) call)->event;
  384.     static mstate, omx, omy, mx, my;
  385.     
  386.  
  387.     switch(event->type) {
  388.     case ButtonPress:
  389.         if (event->xbutton.button == Button1) {
  390.             mstate |= 1;
  391.         } else if (event->xbutton.button == Button2) {
  392.             mstate |= 2;
  393.         } else if (event->xbutton.button == Button3) {
  394.             mstate |= 4;
  395.         }
  396.     mx = event->xbutton.x;
  397.     my = event->xbutton.y;
  398.         break;
  399.     case ButtonRelease:
  400.         if (event->xbutton.button == Button1)
  401.             mstate &= ~1;
  402.         if (event->xbutton.button == Button2)
  403.             mstate &= ~2;
  404.         else if (event->xbutton.button == Button3)
  405.             mstate &= ~4;
  406.         break;
  407.     case MotionNotify:
  408.     if (mstate) {
  409.         omx = mx;
  410.         omy = my;
  411.         mx = event->xbutton.x;
  412.         my = event->xbutton.y;
  413.         if (mstate & 1) {
  414.         transX += mx - omx;
  415.         transY += omy - my;
  416.         }
  417.         if (mstate & 2) {
  418.         rotX += my - omy;
  419.         rotY += mx - omx;
  420.         }
  421.         if (mstate & 4) {
  422.         rotZ += mx - omx + omy - my;
  423.         }
  424.     }
  425.     redraw();
  426.         break;
  427.     case KeyRelease:
  428.         XLookupString(&event->xkey, buf, sizeof buf, &keysym, NULL);
  429.         switch(keysym) {
  430.     case '=':
  431.         scale += 1.0;
  432.         redraw();
  433.         break;
  434.     case '-':
  435.         scale -= 1.0;
  436.         redraw();
  437.         break;
  438.         case XK_Escape:
  439.         glcDeleteContext(contextID);
  440.             exit(EXIT_SUCCESS);
  441.             break;
  442.         default:
  443.         break;
  444.     }
  445.     default:
  446.     break;
  447.     }
  448. }
  449.  
  450. void fontMenuCB(Widget w, XtPointer client_data, XtPointer call_data)
  451. {
  452.     set_font((GLint) client_data - fontBase);
  453.     reset_bounds();
  454.     redraw();
  455. }
  456.  
  457. void menuCB(Widget w, XtPointer client_data, XtPointer call_data)
  458. {
  459.     int cmd = (int) client_data;
  460.  
  461.     switch (cmd) {
  462.     case XX_BITMAP:
  463.     case XX_TRIANGLE:
  464.     case XX_LINE:
  465.     set_draw_style(cmd);
  466.     redraw();
  467.     break;
  468.     case XX_RESETVIEW:
  469.     reset_view();
  470.     redraw();
  471.     break;
  472.     case XX_RESETMODE:
  473.     reset_modes();
  474.     redraw();
  475.     break;
  476.     case XX_ORTHO:
  477.     use_ortho = !use_ortho;
  478.     reset_proj();
  479.     redraw();
  480.     break;
  481.     case XX_QUIT:
  482.     glcDeleteContext(contextID);
  483.     exit(EXIT_SUCCESS);
  484.     default:
  485.     break;
  486.     }
  487. }
  488.  
  489. Widget create_pane(Widget parent)
  490. {
  491.     Arg args[10];
  492.     Cardinal nn;
  493.  
  494.     nn = 0;
  495.     return XmCreatePulldownMenu(parent, "pane", args, nn);
  496. }
  497.  
  498. Widget create_cascade(Widget parent, Widget pane, char *label)
  499. {
  500.     Arg args[10];
  501.     Cardinal nn;
  502.  
  503.     nn = 0;
  504.     XtSetArg(args[nn], XmNsubMenuId, pane); nn++;
  505.     return XmCreateCascadeButtonGadget(parent, label, args, nn);
  506. }
  507.  
  508. Widget create_toggle(Widget parent, char *label, int cmd, void *callback)
  509. {
  510.     Arg args[10];
  511.     Cardinal nn;
  512.     Widget toggle;
  513.  
  514.     nn = 0;
  515.     XtSetArg(args[nn], XmNvisibleWhenOff, False); nn++;
  516.     toggle = XmCreateToggleButtonGadget(parent, label, args, nn);
  517.     XtAddCallback(toggle, XmNvalueChangedCallback, callback, (XtPointer)cmd);
  518.     menu_buttons[cmd] = toggle;
  519.     return toggle;
  520. }
  521.  
  522. Widget create_submenu(Widget parent, MenuPane *data)
  523. {
  524.     Widget pane, cascade;
  525.     Widget items[20];
  526.     int ii;
  527.  
  528.     pane = create_pane(parent);
  529.     cascade = create_cascade(parent, pane, data->label);
  530.     for (ii = 0; ii < data->icount; ii++)
  531.     items[ii] =
  532.         create_toggle(pane, data->items[ii].label, data->items[ii].cmd,
  533.               menuCB);
  534.     XtManageChildren(items, data->icount);
  535.     return cascade;
  536. }
  537.  
  538. Widget create_fontmenu(Widget parent)
  539. {
  540.     Widget pane, cascade;
  541.     Widget *items;
  542.     int ii;
  543.  
  544.     items = (Widget *) alloca(fontCount * sizeof(Widget));
  545.  
  546.     pane = create_pane(parent);
  547.     cascade = create_cascade(parent, pane, "Family");
  548.     for (ii = 0; ii < fontCount; ii++)
  549.     items[ii] =
  550.         create_toggle(pane, fontNames[ii], fontBase + ii, fontMenuCB);
  551.     XtManageChildren(items, fontCount);
  552.     return cascade;
  553. }
  554.  
  555. Widget create_menu(Widget parent)
  556. {
  557.     Widget    menu, pane;
  558.     Arg        args[10];
  559.     Widget    cb[10];
  560.     Cardinal    nn;
  561.     int        button_count;
  562.  
  563.     nn = 0;
  564.     XtSetArg(args[nn], XmNrightAttachment, XmATTACH_FORM); nn++;
  565.     XtSetArg(args[nn], XmNleftAttachment, XmATTACH_FORM); nn++;
  566.     XtSetArg(args[nn], XmNtopAttachment, XmATTACH_FORM); nn++;
  567.     menu = XmCreateMenuBar(parent, "menuBar", args, nn);
  568.  
  569.     fontBase = view_menu.icount + style_menu.icount;
  570.     button_count = fontBase + fontCount;
  571.     menu_buttons = (Widget *) malloc( button_count * sizeof(Widget) );
  572.  
  573.     nn = 0;
  574.     cb[nn++] = create_submenu(menu, &view_menu);
  575.     cb[nn++] = create_submenu(menu, &style_menu);
  576.     cb[nn++] = create_fontmenu(menu);
  577.     XtManageChildren(cb, nn);
  578.  
  579.     return menu;
  580. }
  581.  
  582. main(int argc, char *argv[])
  583. {
  584.     Display        *dpy;
  585.     XVisualInfo    *visinfo;
  586.     GLXContext      ctx;
  587.     Widget          toplevel, form, frame, menu;
  588.     Arg            args[10];
  589.     Cardinal        nn;
  590.     XtAppContext    appctx;
  591.  
  592.     toplevel = XtOpenApplication(&appctx, "animate", NULL, 0,
  593.                  &argc, argv, fallbackResources,
  594.                  applicationShellWidgetClass, NULL, 0);
  595.     dpy = XtDisplay(toplevel);
  596.  
  597.     InitFonts();
  598.  
  599.     nn = 0;
  600.     form = XmCreateForm(toplevel, "form", args, nn);
  601.  
  602.     menu = create_menu(form);
  603.     XtManageChild(menu);
  604.  
  605.     nn = 0;
  606.     XtSetArg(args[nn], XmNtopAttachment, XmATTACH_WIDGET); nn++;
  607.     XtSetArg(args[nn], XmNtopWidget, menu); nn++;
  608.     XtSetArg(args[nn], XmNleftAttachment, XmATTACH_FORM); nn++;
  609.     XtSetArg(args[nn], XmNrightAttachment, XmATTACH_FORM); nn++;
  610.     XtSetArg(args[nn], XmNbottomAttachment, XmATTACH_FORM); nn++;
  611.     frame = XmCreateFrame(form, "frame", args, nn);
  612.     XtManageChild(frame);
  613.  
  614.     /* specify visual directly */
  615.     if (!(visinfo = glXChooseVisual(dpy, DefaultScreen(dpy), attribs)))
  616.         XtAppError(appctx, "no suitable RGB visual");
  617.  
  618.     nn = 0;
  619.     XtSetArg(args[nn], GLwNvisualInfo, visinfo); nn++;
  620.     canvas = XtCreateWidget("canvas", glwMDrawingAreaWidgetClass, 
  621.                  frame, args, nn);
  622.  
  623.     ctx = glXCreateContext(dpy, visinfo, 0, GL_TRUE);
  624.     XtAddCallback(canvas, GLwNginitCallback, initCB, ctx);
  625.     XtAddCallback(canvas, GLwNexposeCallback, expose, ctx);
  626.     XtAddCallback(canvas, GLwNresizeCallback, resize, ctx);
  627.     XtAddCallback(canvas, GLwNinputCallback, input, ctx);
  628.     XtManageChild(canvas);
  629.  
  630.     XtManageChild(form);
  631.     XtRealizeWidget(toplevel);
  632.  
  633.     XtAppMainLoop(appctx);
  634. }
  635.